package com.isoft.airportsystem.service.impl.change;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.isoft.airportsystem.common.change.Result;
import com.isoft.airportsystem.common.enums.RequestStatus;
import com.isoft.airportsystem.entity.change.Flight;
import com.isoft.airportsystem.entity.change.FlightChangeHistory;
import com.isoft.airportsystem.entity.change.FlightChangeRequest;
import com.isoft.airportsystem.entity.dao.FlightChangeEvent;
import com.isoft.airportsystem.entity.dao.FlightChangeRequestDTO;
import com.isoft.airportsystem.entity.dao.PageQuery;
import com.isoft.airportsystem.exception.BusinessException;
import com.isoft.airportsystem.mapper.change.FlightChangeHistoryMapper;
import com.isoft.airportsystem.mapper.change.FlightChangeRequestMapper;
import com.isoft.airportsystem.mapper.change.FlightchangeMapper;
import com.isoft.airportsystem.service.change.EmailNotificationService;
import com.isoft.airportsystem.service.change.FlightChangeService;
import com.isoft.airportsystem.service.change.NotificationService;
import com.isoft.airportsystem.service.validation.ChangeDataValidator;
import com.isoft.airportsystem.service.validation.FlightChangeValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Slf4j
@Service
public class FlightChangeServiceImpl implements FlightChangeService {

    private final FlightChangeRequestMapper requestMapper;
    private final FlightChangeHistoryMapper historyMapper;
    private final NotificationService notificationService;
    private final FlightchangeMapper flightMapper;
    private final FlightChangeValidator flightValidator;
    private final ChangeDataValidator dataValidator;
    private final ObjectMapper objectMapper;
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    private final EmailNotificationService emailNotificationService;

    public FlightChangeServiceImpl(FlightChangeRequestMapper requestMapper,
                                   FlightChangeHistoryMapper historyMapper,
                                   NotificationService notificationService,
                                   FlightchangeMapper flightMapper,
                                   FlightChangeValidator flightValidator,
                                   ChangeDataValidator dataValidator,
                                   ObjectMapper objectMapper,
                                   EmailNotificationService emailNotificationService) {
        this.requestMapper = requestMapper;
        this.historyMapper = historyMapper;
        this.notificationService = notificationService;
        this.flightMapper = flightMapper;
        this.flightValidator = flightValidator;
        this.dataValidator = dataValidator;
        this.objectMapper = objectMapper;
        this.emailNotificationService = emailNotificationService;
    }

    // 提交航班变更请求
    @Override
    @Transactional
    public Result<FlightChangeRequest> submitChangeRequest(FlightChangeRequestDTO dto) {
        try {
            // 1. 验证航班状态是否允许变更
            flightValidator.validateFlightForChange(dto.getFlightId(), dto.getRequestType());

            // 2. 验证变更数据合法性
            String jsonData = convertToJsonSafely(dto.getRequestData());
            dataValidator.validateAndParseChangeData(dto.getRequestType(), jsonData);

            // 3. 创建变更申请
            FlightChangeRequest request = new FlightChangeRequest();
            BeanUtils.copyProperties(dto, request);
            request.setRequestId(UUID.randomUUID().toString());
            request.setRequestStatus(RequestStatus.PENDING);
            request.setApplyTime(new Date());
            request.setRequestData(jsonData); // 设置已经序列化的JSON数据
            requestMapper.insert(request);

            // 4. 记录变更历史
            recordChangeHistory(
                    request.getFlightId(),
                    "APPLY",
                    jsonData, // 使用相同的JSON数据
                    dto.getApplicantId(),
                    dto.getApplicantName(),
                    request.getRequestId()
            );

            // 5. 触发通知
            triggerNotification(request, "SUBMIT", dto.getApplicantName());

            return Result.success(request);
        } catch (Exception e) {
            log.warn("变更申请处理失败: {}", e.getMessage());
            return Result.fail(e instanceof BusinessException ?
                            ((BusinessException) e).getCode() : 500,
                    e.getMessage());
        }
    }

    // 审核变更请求
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<FlightChangeRequest> reviewChangeRequest(String requestId, String status,
                                                           String comment, String reviewerId) {
        try {
            FlightChangeRequest request = requestMapper.selectById(requestId);
            if (request == null) {
                return Result.fail("变更申请不存在");
            }

            // 状态转换验证
            if (!isValidStatusTransition(request.getRequestStatus().name(), status)) {
                return Result.fail("无效的状态转换: " + request.getRequestStatus() + " -> " + status);
            }

            request.setRequestStatus(RequestStatus.valueOf(status));
            request.setReviewerId(reviewerId);
            request.setReviewTime(new Date());
            request.setReviewComment(comment);
            requestMapper.updateById(request);

            recordChangeHistory(
                    request.getFlightId(),
                    "REVIEW_" + status,
                    "审核意见: " + comment,
                    reviewerId,
                    "审核人",
                    requestId
            );

            String changeDataForEvent = null;
            if ("APPROVED".equals(status)) {
                try {
                    // 在应用变更前再次验证航班状态
                    flightValidator.validateFlightForChange(request.getFlightId(), request.getRequestType());

                    // 获取变更前的航班信息
                    Flight beforeFlight = flightMapper.selectById(request.getFlightId());
                    Map<String, Object> beforeMap = new HashMap<>();
                    if (beforeFlight != null) {
                        beforeMap.put("departureAirport", beforeFlight.getDepartureAirport());
                        beforeMap.put("arrivalAirport", beforeFlight.getArrivalAirport());
                        beforeMap.put("departureTime", beforeFlight.getDepartureTime());
                        beforeMap.put("arrivalTime", beforeFlight.getArrivalTime());
                        beforeMap.put("gate", beforeFlight.getGate());
                        beforeMap.put("status", beforeFlight.getStatus());
                        beforeMap.put("remarks", beforeFlight.getRemarks());
                    }

                    // 解析变更数据
                    Map<String, Object> changeMap = dataValidator.validateAndParseChangeData(request.getRequestType(), request.getRequestData());

                    // 应用变更
                    applyFlightChange(request.getFlightId(), request.getRequestType(), request.getRequestData());

                    // 获取变更后的航班信息
                    Flight afterFlight = flightMapper.selectById(request.getFlightId());
                    Map<String, Object> afterMap = new HashMap<>();
                    if (afterFlight != null) {
                        afterMap.put("departureAirport", afterFlight.getDepartureAirport());
                        afterMap.put("arrivalAirport", afterFlight.getArrivalAirport());
                        afterMap.put("departureTime", afterFlight.getDepartureTime());
                        afterMap.put("arrivalTime", afterFlight.getArrivalTime());
                        afterMap.put("gate", afterFlight.getGate());
                        afterMap.put("status", afterFlight.getStatus());
                        afterMap.put("remarks", afterFlight.getRemarks());
                    }

                    // 组装变更前后对比
                    List<HashMap<String, String>> changeList = new ArrayList<>();
                    // 字段名与中文名映射
                    HashMap<String, String> fieldNames = new HashMap<>();
                    fieldNames.put("departureAirport", "起飞机场");
                    fieldNames.put("arrivalAirport", "到达机场");
                    fieldNames.put("departureTime", "起飞时间");
                    fieldNames.put("arrivalTime", "到达时间");
                    fieldNames.put("gate", "登机口");
                    fieldNames.put("status", "状态");
                    fieldNames.put("remarks", "备注");
                    for (String key : fieldNames.keySet()) {
                        String oldVal = beforeMap.get(key) == null ? "" : beforeMap.get(key).toString();
                        String newVal = afterMap.get(key) == null ? "" : afterMap.get(key).toString();
                        if (!oldVal.equals(newVal)) {
                            HashMap<String, String> item = new HashMap<>();
                            item.put("field", fieldNames.get(key));
                            item.put("old", oldVal);
                            item.put("new", newVal);
                            changeList.add(item);
                        }
                    }
                    changeDataForEvent = objectMapper.writeValueAsString(changeList);

                    // 更新状态为已处理
                    request.setRequestStatus(RequestStatus.PROCESSED);
                    requestMapper.updateById(request);

                    // === 新增：无论是否订阅，直接给申请人邮箱发邮件 ===
                    String applicantEmail = request.getEmail(); // 假设有getEmail()
                    if (applicantEmail != null && !applicantEmail.isEmpty()) {
                        FlightChangeEvent event = new FlightChangeEvent(
                                request.getFlightId(),
                                request.getRequestId(),
                                "REVIEW_APPROVED",
                                request.getRequestType(),
                                request.getRequestStatus().name(),
                                reviewerId,
                                changeDataForEvent,
                                "航班变更事件通知"
                        );
                        emailNotificationService.sendFlightChangeNotification(null, event, applicantEmail);
                    }
                    // === 新增代码结束 ===

                } catch (BusinessException e) {
                    log.error("航班变更失败: {}", e.getMessage());
                    // 记录变更失败历史
                    recordChangeHistory(
                            request.getFlightId(),
                            "APPLY_FAILED",
                            "变更失败原因: " + e.getMessage(),
                            "SYSTEM",
                            "系统",
                            requestId
                    );
                    return Result.fail(e.getCode(), e.getMessage());
                }
            }

            // 触发通知时传递详细changeData
            triggerNotificationWithChangeData(request, "REVIEW_" + status, reviewerId, changeDataForEvent);

            return Result.success(request);
        } catch (Exception e) {
            log.error("审核变更请求失败: {}", e.getMessage());
            return Result.fail(500, "处理请求时发生错误: " + e.getMessage());
        }
    }

    // 获取变更申请
    @Override
    public Page<FlightChangeRequest> getChangeRequests(PageQuery query, String flightId, String status) {
        log.info("获取变更申请列表 - 页码: {}, 每页大小: {}, 航班号: {}, 状态: {}",
                query.getPageNum(), query.getPageSize(), flightId, status);

        Page<FlightChangeRequest> page = new Page<>(query.getPageNum(), query.getPageSize());
        QueryWrapper<FlightChangeRequest> wrapper = new QueryWrapper<>();

        if (StringUtils.isNotBlank(flightId)) {
            wrapper.eq("flight_id", flightId);
        }
        if (StringUtils.isNotBlank(status)) {
            wrapper.eq("request_status", status);
        }

        // 按申请时间倒序排列
        wrapper.orderByDesc("apply_time");

        try {
            Page<FlightChangeRequest> result = requestMapper.selectPage(page, wrapper);
            log.info("查询结果 - 总记录数: {}, 当前页记录数: {}, 总页数: {}",
                    result.getTotal(), result.getRecords().size(), result.getPages());
            return result;
        } catch (Exception e) {
            log.error("查询变更申请列表失败: {}", e.getMessage(), e);
            throw new BusinessException("查询变更申请列表失败: " + e.getMessage());
        }
    }

    // 获取变更记录
    @Override
    public Page<FlightChangeHistory> getChangeHistory(PageQuery query, String flightId, String userId) {
        log.info("获取变更历史记录 - 页码: {}, 每页大小: {}, 航班号: {}, 用户ID: {}",
                query.getPageNum(), query.getPageSize(), flightId, userId);

        Page<FlightChangeHistory> page = new Page<>(query.getPageNum(), query.getPageSize());
        QueryWrapper<FlightChangeHistory> wrapper = new QueryWrapper<>();

        if (StringUtils.isNotBlank(flightId)) {
            wrapper.eq("flight_id", flightId);
        }
        if (StringUtils.isNotBlank(userId)) {
            wrapper.eq("operator_id", userId);
        }

        // 按时间倒序排列
        wrapper.orderByDesc("change_time");

        try {
            Page<FlightChangeHistory> result = historyMapper.selectPage(page, wrapper);
            log.info("查询结果 - 总记录数: {}, 当前页记录数: {}, 总页数: {}",
                    result.getTotal(), result.getRecords().size(), result.getPages());
            return result;
        } catch (Exception e) {
            log.error("查询变更历史记录失败: {}", e.getMessage(), e);
            throw new BusinessException("查询变更历史记录失败: " + e.getMessage());
        }
    }

    private boolean isValidStatusTransition(String currentStatus, String newStatus) {
        return switch (currentStatus) {
            case "PENDING" -> "APPROVED".equals(newStatus) || "REJECTED".equals(newStatus);
            case "APPROVED" -> "PROCESSED".equals(newStatus);
            case "REJECTED" -> false;
            default -> false;
        };
    }

    // 处理航班变更
    private void applyFlightChange(String flightId, String changeType, String changeData) {
        try {
            // 验证并解析变更数据
            Map<String, Object> changeMap = dataValidator.validateAndParseChangeData(changeType, changeData);

            // 获取航班信息
            Flight flight = flightMapper.selectById(flightId);
            if (flight == null) {
                throw new BusinessException("航班不存在: " + flightId);
            }

            // 根据变更类型执行更新逻辑
            switch (changeType) {
                case "DELAY" -> applyDelayChange(flight, changeMap);
                case "CANCEL" -> applyCancelChange(flight, changeMap);
                case "DIVERT" -> applyDivertChange(flight, changeMap);
                case "GATE_CHANGE" -> applyGateChange(flight, changeMap);
                case "TIME_ADJUSTMENT" -> applyTimeAdjustment(flight, changeMap);
                default -> throw new BusinessException("未知的变更类型: " + changeType);
            }

            // 更新航班信息
            flight.setLastUpdateTime(new Date());
            flightMapper.updateById(flight);
            log.info("航班 {} 信息已更新: {}", flightId, changeType);

        } catch (Exception e) {
            throw new BusinessException("解析或应用变更数据失败: " + e.getMessage());
        }
    }

    // 处理延误变更
    private void applyDelayChange(Flight flight, Map<String, Object> changeMap) {
        String originalTime = flight.getDepartureTime();
        String newTime = (String) changeMap.get("newTime");

        if (!isLaterTime(originalTime, newTime)) {
            throw new BusinessException("新时间必须晚于原时间: " + originalTime + " -> " + newTime);
        }

        // 更新航班信息
        flight.setDepartureTime(newTime);

        // 只有在非延误状态下才更新状态
        if (!"DELAYED".equals(flight.getStatus())) {
            flight.setStatus("DELAYED");
        }

        // 记录延误原因
        flight.setRemarks("延误原因: " + changeMap.get("reason"));
    }

    // 取消航班变更
    private void applyCancelChange(Flight flight, Map<String, Object> changeMap) {
        // 更新航班状态为取消
        flight.setStatus("CANCELLED");

        // 记录取消原因
        flight.setRemarks("取消原因: " + changeMap.get("reason"));

        // 可选：如果有替代航班，记录信息
        if (changeMap.containsKey("alternativeFlight")) {
            flight.setRemarks(flight.getRemarks() +
                    ", 替代航班: " + changeMap.get("alternativeFlight"));
        }
    }

    // 处理取消航班的替代航班
    private void applyDivertChange(Flight flight, Map<String, Object> changeMap) {
        // 更新目的地机场
        String newDestination = (String) changeMap.get("newDestination");
        flight.setArrivalAirport(newDestination);

        // 更新航班状态为备降
        flight.setStatus("DIVERTED");

        // 记录备降原因
        flight.setRemarks("备降原因: " + changeMap.get("reason"));
    }

    private void applyGateChange(Flight flight, Map<String, Object> changeMap) {
        // 更新登机口信息
        String newGate = (String) changeMap.get("newGate");
        flight.setGate(newGate);

        // 记录变更原因
        flight.setRemarks("登机口变更: " + changeMap.get("reason"));
    }

    // 添加时间调整应用方法
    private void applyTimeAdjustment(Flight flight, Map<String, Object> changeMap) {
        String newDeparture = (String) changeMap.get("newDepartureTime");
        String newArrival = (String) changeMap.get("newArrivalTime");

        // 验证新时间格式
        validateTimeFormat(newDeparture);
        validateTimeFormat(newArrival);

        // 更新航班信息
        flight.setDepartureTime(newDeparture);
        flight.setArrivalTime(newArrival);

        // 记录调整原因
        String reason = (String) changeMap.get("reason");
        flight.setRemarks("时间调整原因: " + reason);

        // 如果是从延误状态调整，更新状态为准点
        if ("DELAYED".equals(flight.getStatus())) {
            flight.setStatus("ON_TIME");
        }
    }

    // 提取时间格式验证方法
    private void validateTimeFormat(String time) {
        try {
            LocalDateTime.parse(time, formatter);
        } catch (DateTimeParseException e) {
            throw new BusinessException("时间格式错误: " + time + "，应为 yyyy-MM-dd HH:mm");
        }
    }

    // 提取时间比较方法
    private boolean isLaterTime(String time1, String time2) {
        try {
            LocalDateTime t1 = LocalDateTime.parse(time1, formatter);
            LocalDateTime t2 = LocalDateTime.parse(time2, formatter);
            return t2.isAfter(t1);
        } catch (DateTimeParseException e) {
            throw new BusinessException("时间格式错误: " + time1 + " 或 " + time2);
        }
    }

    private void recordChangeHistory(String flightId, String action, String details,
                                     String operatorId, String operatorName, String requestId) {
        try {
            FlightChangeHistory history = new FlightChangeHistory();
            history.setFlightId(flightId);
            history.setChangeType(action);
            history.setChangeData(details);
            history.setChangeTime(new Date());
            history.setOperatorId(operatorId);
            history.setOperatorName(operatorName);
            history.setRequestId(requestId);
            historyMapper.insert(history);
        } catch (Exception e) {
            log.error("记录变更历史失败: {}", e.getMessage());
        }
    }

    // 触发通知
    private void triggerNotification(FlightChangeRequest request, String eventType, String operator) {
        try {
            // 创建并发送变更事件通知
            notificationService.sendChangeNotification(
                    new FlightChangeEvent(
                            request.getFlightId(),
                            request.getRequestId(),
                            eventType,
                            request.getRequestType(),
                            request.getRequestStatus().name(),
                            operator,
                            request.getRequestData(),
                            "航班变更事件通知"
                    )
            );
        } catch (Exception e) {
            log.error("触发通知失败: {}", e.getMessage());
        }
    }

    // 新增：带changeData参数的通知
    private void triggerNotificationWithChangeData(FlightChangeRequest request, String eventType, String operator, String changeData) {
        try {
            notificationService.sendChangeNotification(
                    new FlightChangeEvent(
                            request.getFlightId(),
                            request.getRequestId(),
                            eventType,
                            request.getRequestType(),
                            request.getRequestStatus().name(),
                            operator,
                            changeData != null ? changeData : request.getRequestData(),
                            "航班变更事件通知"
                    )
            );
        } catch (Exception e) {
            log.error("触发通知失败: {}", e.getMessage());
        }
    }

    /**
     * 安全地将对象转换为JSON字符串
     * @param data 要转换的对象
     * @return JSON字符串
     */
    private String convertToJsonSafely(Object data) {
        try {
            return objectMapper.writeValueAsString(data);
        } catch (JsonProcessingException e) {
            log.error("JSON转换失败: {}", e.getMessage());
            throw new BusinessException("转换数据为JSON格式失败: " + e.getMessage());
        }
    }
}